Day08 是要利用 HTML5 Canvas 來做出畫布
canvasRef, ctxRef 用來取得顯示的內容
isDrawing 判斷是否正在繪圖
hue 動態改變線條的顏色
direction 控制變化的方向
lastPositionRef 紀錄之前的繪圖定位
const canvasRef = useRef<HTMLCanvasElement | null>(null);
const ctxRef = useRef<CanvasRenderingContext2D | null>(null);
const [isDrawing, setIsDrawing] = useState<boolean>(false);
const [hue, setHue] = useState<number>(0);
const [direction, setDirection] = useState<boolean>(true);
const lastPositionRef = useRef<Position>({ x: 0, y: 0 });
const initializeCanvas = useCallback(() => {
const canvas = canvasRef.current;
if (!canvas) {
return;
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const ctx = canvas.getContext("2d");
if (!ctx) {
return;
}
ctx.strokeStyle = "#BADA55";
ctx.lineJoin = "round";
ctx.lineCap = "round";
ctx.lineWidth = 1;
ctxRef.current = ctx;
}, []);
const draw = useCallback(
(e: React.MouseEvent<HTMLCanvasElement>) => {
if (!isDrawing) {
return;
}
const ctx = ctxRef.current;
if (!ctx) {
return;
}
ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`;
ctx.beginPath();
ctx.moveTo(lastPositionRef.current.x, lastPositionRef.current.y);
ctx.lineTo(e.nativeEvent.offsetX, e.nativeEvent.offsetY);
ctx.stroke();
lastPositionRef.current = {
x: e.nativeEvent.offsetX,
y: e.nativeEvent.offsetY,
};
setHue((prevHue) => (prevHue + 1) % 360);
if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) {
setDirection((prevDirection) => !prevDirection);
}
ctx.lineWidth += direction ? 1 : -1;
},
[isDrawing, hue, direction]
);
const startDrawing = useCallback((e: React.MouseEvent<HTMLCanvasElement>) => {
setIsDrawing(true);
lastPositionRef.current = {
x: e.nativeEvent.offsetX,
y: e.nativeEvent.offsetY,
};
}, []);
const stopDrawing = useCallback(() => {
setIsDrawing(false);
}, []);
const handleResize = useCallback(() => {
initializeCanvas();
}, [initializeCanvas]);
useEffect(() => {
initializeCanvas();
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, [initializeCanvas, handleResize]);
return (
<div className="w-screen h-screen bg-gray-100 p-4">
<canvas
ref={canvasRef}
className="w-full h-full border rounded-md border-gray-300"
onMouseDown={startDrawing}
onMouseMove={draw}
onMouseUp={stopDrawing}
onMouseOut={stopDrawing}
/>
</div>
);